﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Outfish { 

	/// <summary>
	/// Logs validation errors to a directory
	/// Handy for going back and figuring out what the problem was.
	/// </summary>
	public class ContentLoadErrorLogger {
	
		#region constructors (and factory)
		
		/// <summary>
		/// Logs validation errors to users $appPath
		/// </summary>
		/// <param name="applicationName"></param>
		static public ContentLoadErrorLogger FromAppName( string applicationProductName ){
			return new ContentLoadErrorLogger( GetLocalAppPath( applicationProductName ) );
		}
	
		public ContentLoadErrorLogger(string logDirectory){
			this._errorDir = logDirectory;
			
			if( Directory.Exists( this._errorDir ) == false ){
				Directory.CreateDirectory( this._errorDir );
			}
			
		}

		#endregion
		
		/// <summary>
		/// Event handler for screen scraper when there is a validation error.
		/// </summary>
		public void LogValidationError(object sender, ScrapeEventArgs args) {

			try{

				LoadContentException validateException = args.Exception as LoadContentException;
				if( validateException == null ){ return; }
				
				string fileName = this.GetBaseFilename( args.PageType )
					+ "_"
					+ DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
				
				// write info
				File.WriteAllText( fileName +".info", args.Exception.ToString() 
				                  + "\r\nfor: " + args.Request.ToString() 
				);
				File.WriteAllText( fileName +".html", args.Content );

			}
			catch(Exception ex){
				System.Diagnostics.Debug.WriteLine( ex.ToString() ); // logged it
				if( this.ThrowExceptions ){ throw; } // otherwise, swallow it so we don't kill the web scraper
			}

		}

		/// <summary>
		/// Enumerates of existing Logged Errors for the given page type.
		/// </summary>
		/// <param name="pageType"></param>
		/// <returns></returns>
		public IEnumerable<LoggedValidationError> GetLoggedErrors( Type pageType ){
			string basePath = this.GetBaseFilename( pageType );
			
			DirectoryInfo di = new DirectoryInfo( Path.GetDirectoryName( basePath ) );
			FileInfo[] files = di.GetFiles( Path.GetFileName( basePath ) + "*.html" );
			
			foreach( var fi in files ){
				yield return new LoggedValidationError{
					ResponseContent = File.ReadAllText( fi.FullName ),
					FilenameSansExt = Path.GetFileNameWithoutExtension( fi.FullName ),
					LoggedDate = fi.CreationTime,
				};
			}			
		}

		/// <summary>
		/// LogValidationError is allowed to throw an exception.  Default is false since handlers should try to not throw exceptions. 
		/// </summary>
		public bool ThrowExceptions{ get; set; }

		#region private fields
		
		string _errorDir;

		#endregion
		
		#region private methods

		static string GetLocalAppPath(string applicationProductName ){
			if( string.IsNullOrEmpty( applicationProductName ) ){
				throw new InvalidOperationException("Cannot generate LocalAppPath because ProductName is null or empty.");
			}
			string path = Path.Combine(
				 Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData )
				, applicationProductName 
			);
			path = Path.Combine( path, "validationErrors" );
				
			
			if( Directory.Exists( path )==false ){ 
				Directory.CreateDirectory( path ); 
			}
			return path;		
		}
		
		string GetBaseFilename( Type pageType ){
			string pageName = (pageType != null ? pageType.Name : "unknown");
			
			return Path.Combine( this._errorDir, pageName );
			
		}
		#endregion
			
	}

	/// <summary>
	/// Returned by ValidationErrorLogger for existing errors logged to disk
	/// </summary>
	public class LoggedValidationError {
		public string ResponseContent{ get; set; }
		public string FilenameSansExt{ get; set; }
		public string FullPath{ get; set; }
		public DateTime LoggedDate{ get; set; }
	}
}
